﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using Twitterizer;
using Social;


namespace Social.Twitter 
{
	public class TwitterAPI : ISocialNetwork
	{
		     
       private const string FollowerIdsUrlFromat = "http://api.twitter.com/1/followers/ids.json?user_id={0}";
       private const string FollowerUrlFromat = "http://api.twitter.com/1/statuses/followers.json?user_id={0}&cursor=";


	   private readonly ITwitterConfig config;
	   private OAuthTokens _Token;
		public OAuthTokens Token {
			get 
			{ 
				if(_Token == null)
					_Token =  Token = new OAuthTokens { AccessToken = config.AccessToken, AccessTokenSecret = config.AccessTokenSecret, ConsumerKey = config.ConsumerKey, ConsumerSecret = config.ConsumerSecret };
				return _Token;
			}
			set 
			{
				_Token = value;
			}
		}
	   public TwitterAPI(ITwitterConfig config)
	   {
		   this.config = config;
	   }


	   #region ISocialNetwork Members

	   public void Authenticate()
	   {
		   var token = GetTokenFromRequest();
		   config.AccessToken = token.Token;
		   config.AccessTokenSecret = token.TokenSecret;
		   config.Uid = Convert.ToInt64(token.UserId);
		   config.ScreenName = token.ScreenName;
		   config.SaveAccessToken();
	   }

	   public string ConnectUrl
	   {
		   get 
		   {
			   var rToken = OAuthUtility.GetRequestToken(config.ConsumerKey, config.ConsumerSecret, config.RedirectUrl);
			   var url = OAuthUtility.BuildAuthorizationUri(rToken.Token);
			   return url.AbsoluteUri;
		   }
	   }

	   public bool IsAuthenticated
	   {
		   get 
		   { 
				return (!string.IsNullOrEmpty(config.AccessToken) && !string.IsNullOrEmpty(config.AccessTokenSecret));	   
		   }
	   }

	   public void Login()
	   {
		   throw new NotImplementedException();
	   }

	   #endregion


      
       public OAuthTokenResponse GetTokenFromRequest()
       {
           try
           {
               var res = Twitterizer.OAuthUtility.GetAccessTokenDuringCallback(config.ConsumerKey, config.ConsumerSecret);
               return res;
           }
           catch (Exception ex)
           {
               return new OAuthTokenResponse { Token = string.Empty };

           }
       }

       
       public ContentServiceResponse<TwitterStatus> Post(string text)
       {
           var response = new ContentServiceResponse<TwitterStatus>();
           try
           {
			   response.Content = Twitterizer.TwitterStatus.Update(Token, text).ResponseObject;
               response.SetSuccess();
           }
           catch (Exception ex)
           {
               response.SetException(ex);
           }

           return response;


       }

	   public ContentServiceResponse<TwUser> GetUser(decimal id)
	   {
		   return GetUser(id, ""); 
	   }
	   public ContentServiceResponse<TwUser> GetUser(string username)
	   {
		   return GetUser(null, username);
	   }
		
		public ContentServiceResponse<TwUser> GetUser(decimal? id, string username)
       {
           var response = new ContentServiceResponse<TwUser>();
		   try
           {
			   TwitterUser res;
			   if(id.HasValue)
					res =Twitterizer.TwitterUser.Show(Token, id.Value).ResponseObject;
			   else res = Twitterizer.TwitterUser.Show(Token, username).ResponseObject;
               response.Content = new TwUser(res);
               response.SetSuccess();
           }
           catch (Exception ex)
           {
               response.SetException(ex);
           }

           return response;
       }

        public ContentServiceResponse<TwitterUserCollection> GetFolowers(decimal userId)
        {
            return GetFolowers(userId, null);
        }

        public ContentServiceResponse<TwitterUserCollection> GetFolowers(string screenName)
        {
            return GetFolowers(null, screenName);
        }

	   private ContentServiceResponse<TwitterUserCollection> GetFolowers(decimal? userId, String screenName)
	   {
		   var response = new ContentServiceResponse<TwitterUserCollection>();

		   try
		   {

			   response.Content = Twitterizer.TwitterFriendship.Followers(Token, new FollowersOptions() { UserId = userId.HasValue? userId.Value: 0, ScreenName= screenName }).ResponseObject;
			   response.SetSuccess();
		   }
		   catch (Exception ex)
		   {
			   response.SetException(ex);
		   }

		   return response;

	   }

	   public ContentServiceResponse<TwitterUserCollection> GetFriends(decimal userId)
	   {
		   var response = new ContentServiceResponse<TwitterUserCollection>();

		   try
		   {
			   response.Content = Twitterizer.TwitterFriendship.Friends(Token, new FriendsOptions() { UserId = userId }).ResponseObject;
			   response.SetSuccess();
		   }
		   catch (Exception ex)
		   {
			   response.SetException(ex);
		   }

		   return response;

	   }

       public ContentServiceResponse<TwitterStatusCollection> GetRetweets(string statusID)
       {
           var response = new ContentServiceResponse<TwitterStatusCollection>();

           try
           {
               var options = new RetweetsOptions { Count = 200 };
			   response.Content = Twitterizer.TwitterStatus.Retweets(Token, decimal.Parse(statusID), options).ResponseObject;
               response.SetSuccess();
           }
           catch (Exception ex)
           {
               response.SetException(ex);
           }
           return response;
       }
	   public ContentServiceResponse<int> GetRetweetCount(string statusID)
	   {
		   var status = GetStatus(statusID);
		   if (status.ResultOption == ServiceResultOptions.Success)
		   {
			   return new ContentServiceResponse<int> { Content = status.Content.RetweetCount.GetValueOrDefault(), ResultOption = ServiceResultOptions.Success };
		   }

		   return new ContentServiceResponse<int> { ResultOption = status.ResultOption, Message = status.Message };
	   }


		public ContentServiceResponse<TwitterStatus> GetStatus(string statusID)
		{
			var response = new ContentServiceResponse<TwitterStatus>();

			try
			{
				response.Content = Twitterizer.TwitterStatus.Show(Token, decimal.Parse(statusID)).ResponseObject;
				response.SetSuccess();
			}
			catch (Exception ex)
			{
				response.SetException(ex);
			}
			return response;
		}


		public ContentServiceResponse<List<TwStatus>> GetReplies()
       {
           return GetReplies(null);
       }
	   public ContentServiceResponse<List<TwStatus>> GetReplies(string fromStatusID)
       {
		   var response = new ContentServiceResponse<List<TwStatus>>();


           try
           {
               var options = new Twitterizer.TimelineOptions { IncludeRetweets = false, Count = 200, SkipUser= true };
			   options.CacheOutput = false;
			   options.CacheTimespan = TimeSpan.MinValue;			   

               decimal since = new decimal();
               if (!string.IsNullOrEmpty(fromStatusID) && decimal.TryParse(fromStatusID, out since))
                   options.SinceStatusId = since;
			   

               response.Content = TwStatus.GetList(Twitterizer.TwitterTimeline.Mentions(Token, options).ResponseObject);
               response.SetSuccess();
           }
           catch (Exception ex)
           {
               response.SetException(ex);
           }
           return response;
       }

       /// <summary>
       /// Gets the replies for a specified twitter status
       /// </summary>
       /// <param name="statusID">The status for which to get the replies</param>
       /// <param name="fromStatusID">The ID of the last comment to retrieve from. If this argument is null the status ID itself will be used</param>
       /// <returns></returns>
	   public ContentServiceResponse<List<TwStatus>> GetRepliesForStatus(string statusID, string fromStatusID)
       {
           decimal id = new decimal();
           if (string.IsNullOrEmpty(statusID) || !decimal.TryParse(statusID, out id))
			   return new ContentServiceResponse<List<TwStatus>> { ResultOption = ServiceResultOptions.IncorrectParameters };

           //if there is no fromStatusID specified, use the statusId itself.
           if (string.IsNullOrEmpty(fromStatusID))
               fromStatusID = statusID;

           //get all replies for this user
           var response = GetReplies(fromStatusID);
           if (response.ResultOption != ServiceResultOptions.Success)
			   return new ContentServiceResponse<List<TwStatus>> { ResultOption = response.ResultOption, Message = response.Message };
           
           //filter the replies that are not for the specified statusID
           var filtered = response.Content.Where(t => (t.InReplyToStatusId == id));
		   return new ContentServiceResponse<List<TwStatus>> { Content = filtered.ToList(), ResultOption = response.ResultOption };//response.Content = filtered.ToList();
       }

       public static ContentServiceResponse<List<long>> GetFollowerIds(decimal userID)
       {
           var response = new ContentServiceResponse<List<long>>();
           try
           {
               var url = string.Format(FollowerIdsUrlFromat, userID);
               var result = WebReq.GetWebResponse(url);
               response.Content = JSON.DeserializeJSON<List<long>>(result);
               response.SetSuccess();
           }
           catch (Exception ex)
           {
               response.SetException(ex);
           }
           
           return response;
       }

       //public  ContentServiceResponse<List<TwitterUser>> GetFollowers()
       //{
       //    return GetFollowers(-1);
       //}
       public ContentServiceResponse<List<TwitterUser>> GetFollowers(decimal Id)
       {
           var response = new ContentServiceResponse<List<TwitterUser>>();
          
           try
           {
               var options = new FollowersOptions ();
               if (Id != -1)
                   options.UserId = Id;
              
               var result= Twitterizer.TwitterFriendship.Followers(Token, options);
			   var followers =result.ResponseObject; 
			   response.Content = new List<TwitterUser>();

               while((followers != null) && (followers.Count > 0))  
               {
                    foreach (TwitterUser follower in followers)
	                {
                        response.Content.Add(follower);
	                }
                   //if there are no more pages to retrieve, stop the loop
                    if (followers.NextCursor == 0)
                        break;
                   //get the next page
                    followers = followers.NextPage().ResponseObject;
               }
             
               response.SetSuccess();
           }
           catch (Exception ex)
           {
               response.SetException(ex);
           }

           return response;
       }

       public ContentServiceResponse<List<TwitterUser>> GetFollowers(string ID)
       {
            decimal uid;
            if (decimal.TryParse(ID, out uid))
                return GetFollowers(uid);
            else return GetFollowers(-1);
       }
    
       //public ContentServiceResponse<TwitterUserCollection> GetFollowers(decimal ID)
       //{
       //    var response = new ContentServiceResponse<TwitterUserCollection>();

       //    try
       //    {
       //            var options = new FollowersOptions { UserId = ID };
       //            response.Content = Twitterizer.TwitterFriendship.Followers(options);
       //            response.SetSuccess();
       //    }
       //    catch (Exception ex)
       //    {
       //        response.SetException(ex);
       //    }

       //    return response;
       //}

       public class TwUser
	   {
		   #region Properties

		   public DateTime? CreatedDate { get; set; }
		   public string Description { get; set; }
		   public bool? DoesReceiveNotifications { get; set; }
		   public decimal Id { get; set; }
		   public bool IsEmpty { get; set; }
		   public bool IsContributorsEnabled { get; set; }
		   public bool? IsFollowedBy { get; set; }
		   public bool? IsFollowing { get; set; }
		   public bool? IsGeoEnabled { get; set; }
		   public bool? IsProfileBackgroundTiled { get; set; }
		   public bool IsProtected { get; set; }
		   public string Language { get; set; }
		   public string Location { get; set; }
		   public string Name { get; set; }
		   public long NumberOfFavorites { get; set; }
		   public long? NumberOfFollowers { get; set; }
		   public long NumberOfFriends { get; set; }
		   public long NumberOfStatuses { get; set; }
		   //public System.Drawing.Color ProfileBackgroundColor { get; }
		   public string ProfileBackgroundColorString { get; set; }
		   public string ProfileBackgroundImageLocation { get; set; }
		   public string ProfileImageLocation { get; set; }
		   //public System.Drawing.Color ProfileLinkColor { get; }
		   public string ProfileLinkColorString { get; set; }
		   //public System.Drawing.Color ProfileSidebarBorderColor { get; }
		   public string ProfileSidebarBorderColorString { get; set; }
		   //public System.Drawing.Color ProfileTextColor { get; }
		   public string ProfileTextColorString { get; set; }
		   public string ScreenName { get; set; }
		   public TwitterStatus Status { get; set; }
		   public string TimeZone { get; set; }
		   public double? TimeZoneOffset { get; set; }
		   public string Website { get; set; }
		   #endregion


		   public TwUser() { }
           public TwUser(TwitterUser tUser) 
           {
			   if (tUser == null)
				   return;

            this.CreatedDate = tUser.CreatedDate;
            this.Description = tUser.Description;
            this.DoesReceiveNotifications = tUser.DoesReceiveNotifications;
            this.Id = tUser.Id;
           // this.IsEmpty= tUser.IsEmpty;
            this.IsFollowedBy= tUser.IsFollowedBy;
            this.IsFollowing= tUser.IsFollowing;
            this.IsGeoEnabled= tUser.IsGeoEnabled;
            this.IsProfileBackgroundTiled = tUser.IsProfileBackgroundTiled;
            this.IsProtected= tUser.IsProtected;
            this.Language= tUser.Language;
            this.Location = tUser.Location;
            this.Name = tUser.Name;
            this.NumberOfFavorites= tUser.NumberOfFavorites;
            this.NumberOfFollowers = tUser.NumberOfFollowers;
            this.NumberOfFriends = tUser.NumberOfFriends;
            this.NumberOfStatuses = tUser.NumberOfStatuses;
            //this.ProfileBackgroundColor = tUser.ProfileBackgroundColor;
            this.ProfileBackgroundColorString= tUser.ProfileBackgroundColorString;
            this.ProfileBackgroundImageLocation = tUser.ProfileBackgroundImageLocation;
            this.ProfileImageLocation = tUser.ProfileImageLocation;
            //this.ProfileLinkColor= tUser.ProfileLinkColor;
            this.ProfileLinkColorString= tUser.ProfileLinkColorString;
            //this.ProfileSidebarBorderColor
            //this.ProfileSidebarBorderColorString= 
            //this.ProfileTextColor= tUser.IsContributorsEnabled;
            //this.ProfileTextColorString= tUser.IsContributorsEnabled;
            //this.RateLimiting = tUser.IsContributorsEnabled;
            //this.RequestStatus= tUser.IsContributorsEnabled;
            this.ScreenName= tUser.ScreenName;
            //this.Status = tUser.IsContributorsEnabled;
            this.TimeZone = tUser.TimeZone;
            this.TimeZoneOffset = tUser.TimeZoneOffset;
            this.Website = tUser.Website;
            
           }

           public static TwUser Parse(TwitterUser tUser)
           {
               return new TwUser(tUser);
           }
       }

	   public class TwStatus
	   {
		   public DateTime CreatedDate { get; set; }
		   //public TwitterGeo Geo { get; set; }
		   public decimal Id { get; set; }
		   public string InReplyToScreenName { get; set; }
		   public decimal? InReplyToStatusId { get; set; }
		   public decimal? InReplyToUserId { get; set; }
		   public bool? IsFavorited { get; set; }
		   public bool? IsTruncated { get; set; }
		   //public TwitterPlace Place { get; set; }
		   public TwStatus RetweetedStatus { get; set; }
		   public string Source { get; set; }
		   public string Text { get; set; }
		   public TwUser User { get; set; }

		   public TwStatus() { }
		   public TwStatus(TwitterStatus status) 
		   {

			   if (status == null)
				   return;

				this.CreatedDate = status.CreatedDate;
				this.Id = status.Id;
				this.InReplyToScreenName = status.InReplyToScreenName;
				this.InReplyToStatusId = status.InReplyToStatusId;
				this.InReplyToUserId = status.InReplyToUserId;
				this.IsFavorited = status.IsFavorited;
				this.IsTruncated = status.IsTruncated;
				this.RetweetedStatus = new TwStatus(status.RetweetedStatus);
				this.Source = status.Source;
				this.Text = status.Text;
				this.User = new TwUser(status.User);
		   }

		   internal static List<TwStatus> GetList(TwitterStatusCollection twitterStatusCollection)
		   {
			   var list = new List<TwStatus>();
			   foreach (var st in twitterStatusCollection)
			   {
				   list.Add(new TwStatus(st));
			   }

			   return list;
		   }
	   }

	}
}
